package main

import (
	"fmt"
	"github.com/gin-gonic/gin"
	"log"
	"net/http"
)

func main() {
	router := gin.Default()
	//加载模板
	//r.LoadHTMLFiles("templates/posts/index.html", "templates/users/index.html")
	router.LoadHTMLGlob("templates/**/*")

	router.GET("/hello", func(context *gin.Context) {
		context.JSON(200, gin.H{"name": "张三", "age": 22})
	})

	//模板
	router.GET("/posts/index", func(c *gin.Context) {
		c.HTML(http.StatusOK, "posts/index.html", gin.H{
			"title": "posts-index-title",
		})
	})

	router.GET("/users/index", func(c *gin.Context) {
		c.HTML(http.StatusOK, "users/index.html", gin.H{
			"title": "users-index-title",
		})
	})

	//获取 /user/search?username=hh&address=22 参数
	router.GET("/query", func(context *gin.Context) {
		//参数不存在时指定默认值
		username := context.DefaultQuery("username", "默认用户名")
		//参数不存在时返回 类型的 零值
		address := context.Query("address")
		context.JSON(http.StatusOK, gin.H{"username": username, "address": address})
	})

	//获取form表单中的参数
	router.POST("/queryForm", func(context *gin.Context) {
		// DefaultPostForm取不到值时会返回指定的默认值
		//username := context.DefaultPostForm("username", "小王子")

		//参数不存在时返回 类型的 零值
		username := context.PostForm("username")
		address := context.PostForm("address")

		//输出json结果给调用方
		context.JSON(http.StatusOK, gin.H{
			"username": username,
			"address":  address,
		})
	})

	//获取Path参数
	router.GET("/path/:username/:address", func(context *gin.Context) {
		//参数不存在时返回 零值
		username := context.Param("username")
		address := context.Param("address")
		//输出json结果给调用方
		context.JSON(http.StatusOK, gin.H{
			"username": username,
			"address":  address,
		})
	})

	//参数绑定
	/**
	  基于请求的Content-Type识别请求数据类型并利用反射机制自动提取请求中QueryString、form表单、JSON、XML等参数到结构体中。
	  .ShouldBind()强大的功能，它能够基于请求自动提取JSON、form表单和QueryString类型的数据，并把值绑定到指定的结构体对象。
	*/
	//绑定查询参数 /bingQuery?user=hh&password=22
	router.GET("/bingQuery", func(context *gin.Context) {
		var login Login
		//context.ShouldBindJSON(&login)
		if err := context.ShouldBind(&login); err == nil {
			context.JSON(http.StatusOK, login)
		} else {
			context.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		}
	})

	//绑定表单参数
	router.POST("/bindForm", func(context *gin.Context) {
		var login Login
		if err := context.ShouldBind(&login); err == nil {
			context.JSON(http.StatusOK, login)
		} else {
			context.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		}
	})

	//绑定json数据
	router.POST("/bindJson", func(context *gin.Context) {
		var login Login
		if err := context.ShouldBind(&login); err == nil {
			context.JSON(http.StatusOK, login)
		} else {
			context.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		}
	})

	//文件上传
	// 处理multipart forms提交文件时默认的内存限制是32 MiB
	// 可以通过下面的方式修改
	// router.MaxMultipartMemory = 8 << 20  // 8 MiB
	router.POST("/uploadFile", func(context *gin.Context) {
		// 获取单个文件
		file, err := context.FormFile("file")
		if err != nil {
			context.JSON(http.StatusInternalServerError, gin.H{"message": err.Error()})
			return
		}
		filename := file.Filename
		dst := fmt.Sprintf("d:/%s", filename)
		//保存到指定位置
		context.SaveUploadedFile(file, dst)
		context.JSON(http.StatusOK, gin.H{"message": fmt.Sprintf("%s上传成功", filename)})
	})

	//多文件上传
	router.POST("/uploadMulti", func(context *gin.Context) {
		// Multipart form
		form, _ := context.MultipartForm()
		files := form.File["file"]

		for _, file := range files {
			log.Println(file.Filename)
			dst := fmt.Sprintf("d:/%s", file.Filename)
			// 上传文件到指定的目录
			context.SaveUploadedFile(file, dst)
		}
		context.JSON(http.StatusOK, gin.H{
			"message": fmt.Sprintf("%d files uploaded!", len(files)),
		})
	})

	router.Run(":8088")
}

// Login Binding from JSON
type Login struct {
	User     string `form:"user" json:"user" binding:"required"`
	Password string `form:"password" json:"password" binding:"required"`
}
